package com.hyc.proxy;

import com.hyc.config.BreakerConfig;
import com.hyc.config.Resilience4jRetryConfig;
import com.hyc.message.MessageType;
import com.hyc.message.RpcRequest;
import com.hyc.message.RpcResponse;
import com.hyc.netty.client.NettyRpcClient;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.retry.Retry;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.function.Supplier;

/**
 * @author 冷环渊
 * @date 2025/6/6 19:18
 * @description ServiceProxy
 */
public class ServiceProxy implements InvocationHandler {
    private final CircuitBreaker circuitBreaker;
    private final Retry retry;


    public ServiceProxy() {
        this.retry = Resilience4jRetryConfig.GetRetryTemplate();
        this.rpcClient = new NettyRpcClient();
        this.circuitBreaker = BreakerConfig.getCircuitBreaker();
        setupEventListeners();
    }

    NettyRpcClient rpcClient;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        System.out.println("进入方法的类名:" + method.getDeclaringClass().getName());
        RpcRequest request = RpcRequest.builder()
                .requestId(UUID.randomUUID().toString())
                .type(MessageType.REQUEST)
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .params(args)
                .paramsType(method.getParameterTypes()).build();
        RpcResponse response = null;
        boolean checkRetry = rpcClient.getNacosServiceCenter().checkRetry();
        if (checkRetry) {
            //回调函数
            Supplier<RpcResponse> rpcCall = () -> {
                try {
                    return rpcClient.sendRpcRequest(request).get();
                } catch (Exception e) {
                    throw new RuntimeException("请求失败");
                }
            };
            //先熔断再请求
            response = CircuitBreaker.decorateSupplier(circuitBreaker, () -> Retry.decorateSupplier(retry, rpcCall).get()).get();
            return response.getData();
        }
        response = rpcClient.sendRpcRequest(request).get();
        return response.getData();
    }

    public void setupEventListeners() {
        retry.getEventPublisher()
                .onRetry(event -> {
                    System.out.println("重试次数:" + event.getNumberOfRetryAttempts());
                })
                .onError(event -> System.out.println("重试失败"))
                .onSuccess(event -> System.out.println("重试成功"));
        circuitBreaker.getEventPublisher()
                .onStateTransition(event -> {
                    switch (event.getStateTransition()) {
                        case CLOSED_TO_OPEN:
                            System.out.println("熔断器已打开");
                            break;
                        case OPEN_TO_HALF_OPEN:
                            System.out.println("熔断器已半开");
                            break;
                        case HALF_OPEN_TO_CLOSED:
                            System.out.println("熔断器已关闭");
                            break;
                        case HALF_OPEN_TO_OPEN:
                            System.out.println("熔断器半开失败");
                    }
                });
    }

    public <T> T getProxy(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz}, this);
    }
}
